﻿using CMS.Constants;
using CMS.Controls.Events;
using CMS.Dialogs;
using CMS.Infos;
using CMS.REST;
using CMS.Util;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using static CMS.Controls.ScheduleDisplay;

namespace CMS.Controls.DisplayTabPages
{
    public partial class CourseTabPage : MainFormTabPageTemplate
    {
        #region 内部类定义

        /// <summary>
        /// 课程元素适配器
        /// </summary>
        private class CourseAdapter : IAdapter, IDisposable
        {
            /// <summary>
            /// 数据容器
            /// </summary>
            private readonly List<CourseRoom>[] _Items = new List<CourseRoom>[7];

            /// <summary>
            /// 当数据发生了改变时,使用此事件来提示ScheduleDisplay进行刷新
            /// </summary>
            public event EventHandler<ScheduleDisplayEventArgs> DataChanged;

            /// <summary>
            /// 各种不同颜色的画刷
            /// </summary>
            private readonly Brush[] _MyBrushes = new Brush[] {
                new SolidBrush(ColorTranslator.FromHtml("#ff5757")),
                new SolidBrush(ColorTranslator.FromHtml("#ff80bf")),
                new SolidBrush(ColorTranslator.FromHtml("#be77ff")),
                new SolidBrush(ColorTranslator.FromHtml("#a9a9ff")),
                new SolidBrush(ColorTranslator.FromHtml("#85c2ff")),
                new SolidBrush(ColorTranslator.FromHtml("#33bebe")),
                new SolidBrush(ColorTranslator.FromHtml("#34c379")),
                new SolidBrush(ColorTranslator.FromHtml("#8fcc33")),
                new SolidBrush(ColorTranslator.FromHtml("#ffe35d")),
                new SolidBrush(ColorTranslator.FromHtml("#ff9933"))
            };

            /// <summary>
            /// 标题格式
            /// </summary>
            private readonly StringFormat _TitleFormat = new StringFormat() { Alignment = StringAlignment.Center };

            /// <summary>
            /// 标题字体
            /// </summary>
            private readonly Font _TitleFont = new Font("微软雅黑", 12, GraphicsUnit.Pixel);

            /// <summary>
            /// 当元素被选中时的颜色
            /// </summary>
            private readonly Pen _SelectedPen = new Pen(Color.Gray, 1);

            /// <summary>
            /// 当元素被选中时的画刷
            /// </summary>
            private readonly Brush _SelectedBrush = new SolidBrush(Color.FromArgb(60, 0, 0, 0));

            /// <summary>
            /// 文字画刷
            /// </summary>
            private readonly Brush TitleBrush = Brushes.White;

            /// <summary>
            /// 下一个待分配的颜色
            /// </summary>
            private int _Next = 0;

            /// <summary>
            /// 获取下一个颜色
            /// </summary>
            /// <returns></returns>
            private Brush NextBrush()
            {
                if (_Next == _MyBrushes.Length)
                {
                    _Next = 0;
                }

                return _MyBrushes[_Next++];
            }

            /// <summary>
            /// 设置新的课程信息,此函数将会重新设置
            /// </summary>
            /// <param name="courses"></param>
            public void SetCourses(IEnumerable<CourseRoom> courses)
            {
                for (int i = 1; i <= 7; i++)
                {
                    _Items[i - 1] = (from c in courses where c.Week == i select c).ToList();
                    foreach (CourseRoom item in _Items[i - 1])
                    {
                        item.Tag = NextBrush();
                    }
                }
                DataChanged?.Invoke(this, new ScheduleDisplayEventArgs(0));
            }

            /// <summary>
            /// ID相等比较器
            /// </summary>
            private class EQID : IEqualityComparer<CourseRoom>
            {
                public static readonly EQID Instance = new EQID();
                public bool Equals(CourseRoom x, CourseRoom y)
                {
                    return x.ID == y.ID;
                }

                public int GetHashCode(CourseRoom obj)
                {
                    return obj.ID;
                }
            }

            /// <summary>
            /// 提示数据源对数据进行了更新
            /// </summary>
            /// <param name="course"></param>
            public void UpdateCourse(CourseRoom course)
            {
                if (course.Tag == null)
                {
                    course.Tag = NextBrush();
                }
                if (_Items[course.Week - 1].Contains(course))
                {
                    DataChanged?.Invoke(this, new ScheduleDisplayEventArgs(course.Week));
                }
                else
                {
                    for (int i = 0; i < 7; i++)
                    {
                        if (_Items[i].Contains(course, EQID.Instance))
                        {
                            _Items[i].Remove((from item in _Items[i] where item.ID == course.ID select item).First());
                            DataChanged?.Invoke(this, new ScheduleDisplayEventArgs(i + 1));
                            Application.DoEvents();
                            _Items[course.Week - 1].Add(course);
                            DataChanged?.Invoke(this, new ScheduleDisplayEventArgs(course.Week));
                            return;
                        }
                    }
                    DataChanged?.Invoke(this, new ScheduleDisplayEventArgs(0));
                }

            }

            /// <summary>
            /// 新增一个课程信息
            /// </summary>
            /// <param name="course"></param>
            public void AddCourse(CourseRoom course)
            {
                _Items[course.Week - 1].Add(course);
                if (course.Tag == null)
                {
                    course.Tag = NextBrush();
                }
                DataChanged?.Invoke(this, new ScheduleDisplayEventArgs(course.Week));
            }

            /// <summary>
            /// 删除某一个课程
            /// </summary>
            /// <param name="course"></param>
            public void DeleteItem(CourseRoom course)
            {
                for (int i = 1; i <= 7; i++)
                {
                    if (_Items[i - 1].Remove(course))
                    {
                        DataChanged?.Invoke(this, new ScheduleDisplayEventArgs(i));
                        return;
                    }
                }

            }

            /// <summary>
            /// 绘制一个列
            /// </summary>
            /// <param name="week"></param>
            /// <param name="pw"></param>
            /// <param name="ph"></param>
            /// <param name="selected"></param>
            /// <param name="g"></param>
            public void DrawItem(int week, int pw, int ph, Point selected, Graphics g)
            {
                if (_Items[week - 1] != null)
                {
                    foreach (CourseRoom item in _Items[week - 1])
                    {
                        Rectangle rect = new Rectangle(pw * item.Week, item.StartTime * ph, pw, ph * item.TimeSpan);
                        GraphicsPath path = Utils.GetRoundRect(rect.X + 1, rect.Y + 1, rect.Width - 1, rect.Height - 1, 3);
                        g.FillPath(item.Tag as Brush, path);
                        if (item.Week == selected.X && item.StartTime <= selected.Y && selected.Y < item.StartTime + item.TimeSpan)
                        {
                            path = Utils.GetRoundRect(rect.X + 1, rect.Y + 1, rect.Width - 2, rect.Height - 2, 3);
                            g.FillPath(_SelectedBrush, path);
                            g.DrawPath(_SelectedPen, path);
                        }
                        rect.X += 2;
                        rect.Y += 6;
                        rect.Width -= 4;
                        rect.Height -= 12;
                        g.DrawString(item.Name, _TitleFont, TitleBrush, rect, _TitleFormat);
                    }
                }
            }

            /// <summary>
            /// 获取所有的已激活的元素
            /// </summary>
            /// <param name="selected"></param>
            /// <returns></returns>
            public CourseRoom[] GetActiveItems(Point selected)
            {
                if (selected.X <= 0 || selected.X > 7 || selected.Y <= 0 || selected.Y > 14)
                {
                    return new CourseRoom[0];
                }

                return (from item in _Items[selected.X - 1] where item.StartTime <= selected.Y && selected.Y < item.StartTime + item.TimeSpan select item).ToArray();
            }

            private void Dispose(bool isDisposing)
            {
                if (isDisposing)
                {
                    _SelectedBrush.Dispose();
                    _SelectedPen.Dispose();
                    _TitleFont.Dispose();
                }
            }

            public void Dispose()
            {
                Dispose(true);
            }

            ~CourseAdapter()
            {
                Dispose(false);
            }
        }


        #endregion

        #region 私有字段
        /// <summary>
        /// 适配器对象
        /// </summary>
        private CourseAdapter _CourseAdapter = new CourseAdapter();

        /// <summary>
        /// 缓存课程编辑对话框
        /// </summary>
        private CourseEditDialog _CourseEditDialog = null;

        /// <summary>
        /// 当前选择的课程
        /// </summary>
        private CourseRoom _CurCourse = null;

        /// <summary>
        /// 缓存已经打开的排课助手,单例的需要
        /// </summary>
        private ScheduleAdvisor _ScheduleAdvisor = null;


        #endregion

        public CourseTabPage()
        {
            InitializeComponent();
            _Initialize();

            Task.Run(() =>
            {
                _RefreshBasicData();
            });
            _RefreshCourseData(false);
        }

        private void _Initialize()
        {
            //this
            Dock = DockStyle.Fill;

            //SD_Course
            SD_Course.ContextMenuStrip = CMS_Course;
            SD_Course.Adapter = _CourseAdapter;

            //CB_ClassWeek_Course
            CB_ClassWeek.DataSource = Constant.GenClassWeekList();
            CB_ClassWeek.DisplayMember = "Key";
            CB_ClassWeek.ValueMember = "Value";
        }

        #region 数据刷新

        /// <summary>
        /// 刷新基础数据
        /// </summary>
        private void _RefreshBasicData()
        {
            RESTResponse response = RESTClient.IndexManaged("apis/v1/terms");
            if (response.IsSuccess)
            {
                Term[] terms = response.Data.ToObject<Term[]>();
                CB_Term.Invoke(() =>
                {
                    CB_Term.SyncComboBoxData("ID", terms);
                });
            }
            else
            {
                CB_Term.Invoke(() =>
                {
                    CB_Term.SyncComboBoxData("ID", new Term[0]);
                });
            }

            response = RESTClient.IndexManaged("apis/v1/rooms");
            if (response.IsSuccess)
            {
                Room[] rooms = response.Data.ToObject<Room[]>();
                CB_Room.Invoke(() =>
                {
                    CB_Room.SyncComboBoxData("Name", rooms);
                });
            }
            else
            {
                CB_Room.Invoke(() =>
                {
                    CB_Room.SyncComboBoxData("Name", new Room[0]);
                });
            }
        }

        /// <summary>
        /// 刷新课表数据
        /// </summary>
        private void _RefreshCourseData(bool reportError)
        {
            if (_RefreshLock)
            {
                return;
            }

            if (CB_Term.SelectedIndex == -1)
            {
                if (reportError)
                {
                    MessageBox.Show("必须选择一个正确的学期", "错误");
                }

                return;
            }

            if (CB_Room.SelectedIndex == -1)
            {
                if (reportError)
                {
                    MessageBox.Show("必须选择一个正确的课室", "错误");
                }

                return;
            }

            RESTResponse response = RESTClient.IndexManaged("apis/v1/courses_room", new RESTWhere("term_id", CB_Term.SelectedValue), new RESTWhere("room", CB_Room.SelectedValue), new RESTWhere("", "exp", $"class_week&{CB_ClassWeek.SelectedValue}<>0"));
            this.Invoke(() =>
            {
                if (response.IsSuccess)
                {
                    _CourseAdapter.SetCourses(response.Data.ToObject<CourseRoom[]>());
                }
                else
                {
                    _CourseAdapter.SetCourses(new CourseRoom[0]);
                }
                _RefreshCoursePreview();
            });


        }

        /// <summary>
        /// 刷新预览框数据
        /// </summary>
        private void _RefreshCoursePreview()
        {
            LV_Course.BeginUpdate();
            LV_Course.Items.Clear();
            foreach (CourseRoom item in _CourseAdapter.GetActiveItems(SD_Course.SelectedPoint))
            {
                LV_Course.Items.Add(_GenListViewItem(item));
            }
            LV_Course.EndUpdate();
        }

        #region 预览框数据生成
        /// <summary>
        /// 课程元素的标题文字的字体
        /// </summary>
        private static readonly Font _CourseNameFont = new Font("微软雅黑", 16, FontStyle.Bold, GraphicsUnit.Pixel);

        /// <summary>
        /// 课程元素的小属性的字体
        /// </summary>
        private static readonly Font _CourseItemFont = new Font("微软雅黑", 12, GraphicsUnit.Pixel);

        /// <summary>
        /// 生成一个与课程信息对应ListViewItem
        /// </summary>
        /// <param name="courseRoom"></param>
        /// <returns></returns>

        private ListViewItem _GenListViewItem(CourseRoom courseRoom)
        {
            ListViewItem lvi = new ListViewItem
            {
                Text = courseRoom.Name,
                ImageKey = "Course",
                ForeColor = Color.DarkBlue,
                UseItemStyleForSubItems = false,
                Font = _CourseNameFont,
                Tag = courseRoom
            };
            lvi.SubItems.Add(new ListViewItem.ListViewSubItem(lvi, $"{courseRoom.ClassName}({courseRoom.StudentCount}人)") { Name = "className", Font = _CourseItemFont });
            lvi.SubItems.Add(new ListViewItem.ListViewSubItem(lvi, courseRoom.Teacher) { Name = "teacher", Font = _CourseItemFont });
            lvi.SubItems.Add(new ListViewItem.ListViewSubItem(lvi, $"{courseRoom.ClassWeek}周[{courseRoom.ClassTime}节]") { Name = "time", Font = _CourseItemFont });
            return lvi;
        }






        #endregion

        #endregion

        #region 数据更新处理函数
        private void _CourseEditDialog_OnSync(object sender, SyncCourseEventArgs e)
        {
            if (e.IsNew)
            {
                _CourseAdapter.AddCourse(e.Course);
            }
            else
            {
                _CourseAdapter.UpdateCourse(e.Course);
            }
        }

        /// <summary>
        /// 打开课程编辑对话框
        /// </summary>
        /// <param name="course"></param>
        /// <param name="term"></param>
        /// <param name="room"></param>
        /// <param name="isNew"></param>
        private void _StartEditCourse(CourseRoom course, Term term, Room room, ushort week, uint classWeek, uint classTime, bool isNew)
        {
            if (_CourseEditDialog == null || _CourseEditDialog.IsDisposed)
            {
                _CourseEditDialog = new CourseEditDialog();
                _CourseEditDialog.OnSync += _CourseEditDialog_OnSync;
            }
            if (isNew)
            {
                if (course == null)
                {
                    course = new CourseRoom();
                }
                course.Week = week;
                course.ClassWeekRaw = classWeek;
                course.ClassTimeRaw = classTime;
                course.Room = room.Name;
                course.TermID = term.ID;
            }
            else
            {
                if (course == null)
                {
                    throw new ArgumentNullException(nameof(course));
                }
            }

            _CourseEditDialog.CurCourse = course;
            _CourseEditDialog.CurRoom = room;
            _CourseEditDialog.CurTerm = term;
            _CourseEditDialog.IsNew = isNew;

            if (_CourseEditDialog.ShowDialog(this) == DialogResult.OK)
            {

            }
        }

        /// <summary>
        /// 删除课程数据
        /// </summary>
        /// <param name="course"></param>
        private void _DeleteCourse(CourseRoom course)
        {
            if (MessageBox.Show(this, $"确认要删除课程[{course.Name}]吗?", "确认删除", MessageBoxButtons.YesNo) == DialogResult.Yes)
            {
                RESTResponse response = RESTClient.Delete("apis/v1/courses_room", course.ID.ToString());
                if (response.IsSuccess)
                {
                    _CourseAdapter.DeleteItem(course);
                }
                else
                {
                    MessageBox.Show(this, $"删除课程[{course.Name}]失败");
                }
            }
        }
        #endregion


        #region 界面响应函数
        private bool _RefreshLock = false;
        private void Bn_Refresh_Click(object sender, EventArgs e)
        {
            _RefreshLock = true;
            _RefreshBasicData();
            _RefreshLock = false;
            _RefreshCourseData(false);
        }

        private void SD_Course_SelectChanged(object sender, EventArgs e)
        {
            _RefreshCoursePreview();
        }

        private void CB_Term_SelectedIndexChanged(object sender, EventArgs e)
        {
            _RefreshCourseData(false);
        }

        private void CB_ClassWeek_SelectedIndexChanged(object sender, EventArgs e)
        {
            _RefreshCourseData(false);
        }

        private void CB_Room_SelectedIndexChanged(object sender, EventArgs e)
        {
            _RefreshCourseData(false);
        }

        private void CMS_Course_Opening(object sender, CancelEventArgs e)
        {
            if (SD_Course.SelectedPoint.X == 0 || SD_Course.SelectedPoint.Y == 0 || !Permission.CheckPermission(Permission.EditCourseRoom))
            {
                e.Cancel = true;
                return;
            }
            CourseRoom[] items = _CourseAdapter.GetActiveItems(SD_Course.SelectedPoint);

            TSMI_EditCourse.DropDownItems.Clear();
            TSMI_DeleteCourse.DropDownItems.Clear();
            if (items.Length > 0)
            {
                TSMI_EditCourse.Enabled = TSMI_DeleteCourse.Enabled = true;
                foreach (CourseRoom item in items)
                {
                    string itemName = $"{item.Name} {item.ClassWeek}周[{item.ClassTime}节]";
                    TSMI_EditCourse.DropDownItems.Add(new ToolStripMenuItem(itemName, Resource1.Edit16, TSMI_EditItem) { Tag = item });
                    TSMI_DeleteCourse.DropDownItems.Add(new ToolStripMenuItem(itemName, Resource1.Delete16, TSMI_DeleteItem) { Tag = item });
                }
            }
            else
            {
                TSMI_EditCourse.Enabled = TSMI_DeleteCourse.Enabled = false;
            }
        }

        private void TSMI_AddCourse_Click(object sender, EventArgs e)
        {
            if (CB_Term.SelectedIndex == -1)
            {
                MessageBox.Show(this, "必须选择一个学期才能进行编辑");
                return;
            }

            if (CB_Room.SelectedIndex == -1)
            {
                MessageBox.Show(this, "必须选择一个课室才能进行编辑");
                return;
            }

            _StartEditCourse(null, (Term)CB_Term.SelectedItem, (Room)CB_Room.SelectedItem, (ushort)SD_Course.SelectedPoint.X, (1 << 17) - 1, 3u << (SD_Course.SelectedPoint.Y - 1), true);
        }

        /// <summary>
        /// 编辑课表元素
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TSMI_EditItem(object sender, EventArgs e)
        {
            if (CB_Term.SelectedIndex == -1)
            {
                MessageBox.Show(this, "必须选择一个学期才能进行编辑");
                return;
            }

            if (CB_Room.SelectedIndex == -1)
            {
                MessageBox.Show(this, "必须选择一个课室才能进行编辑");
                return;
            }
            CourseRoom tag = (CourseRoom)(sender as ToolStripMenuItem).Tag;
            _StartEditCourse(tag, (Term)CB_Term.SelectedItem, (Room)CB_Room.SelectedItem, 0, 0, 0, false);

        }

        /// <summary>
        /// 删除课表
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TSMI_DeleteItem(object sender, EventArgs e)
        {
            CourseRoom tag = (CourseRoom)(sender as ToolStripMenuItem).Tag;
            _DeleteCourse(tag);
        }









        #endregion

        private void CMS_CourseLV_Opening(object sender, CancelEventArgs e)
        {
            if (LV_Course.SelectedItems.Count != 1 || !Permission.CheckPermission(Permission.EditCourseRoom))
            {
                e.Cancel = true;
                return;
            }
            else
            {
                _CurCourse = LV_Course.SelectedItems[0].Tag as CourseRoom;
            }
        }

        private void TSMI_EditThisCourse_Click(object sender, EventArgs e)
        {
            if (CB_Term.SelectedIndex == -1)
            {
                MessageBox.Show(this, "必须选择一个学期才能进行编辑");
                return;
            }

            if (CB_Room.SelectedIndex == -1)
            {
                MessageBox.Show(this, "必须选择一个课室才能进行编辑");
                return;
            }


            _StartEditCourse(_CurCourse, (Term)CB_Term.SelectedItem, (Room)CB_Room.SelectedItem, 0, 0, 0, false);
        }

        private void TSMI_DeleteThisCourse_Click(object sender, EventArgs e)
        {
            if (_CurCourse != null)
            {
                _DeleteCourse(_CurCourse);
            }
        }


        private void TSMI_ScheduleAdvisor_Click(object sender, EventArgs e)
        {
            if (_ScheduleAdvisor == null || _ScheduleAdvisor.IsDisposed)
            {
                _ScheduleAdvisor = new ScheduleAdvisor
                {
                    CurTerm = CB_Term.SelectedItem as Term
                };
                _ScheduleAdvisor.CreateCourse += _ScheduleAdvisor_SelectRoom;
            }
            if (_ScheduleAdvisor.Visible)
            {
                _ScheduleAdvisor.Activate();
            }
            else
            {
                _ScheduleAdvisor.Show(this);
            }
        }

        private void _ScheduleAdvisor_SelectRoom(object sender, CreateCourseEventArgs e)
        {
            System.Collections.IEnumerator i = CB_Room.Items.GetEnumerator();
            while (i.MoveNext())
            {
                Room item = (Room)i.Current;
                if (item.Name == e.Room)
                {
                    CB_Room.SelectedItem = i.Current;

                    _StartEditCourse(null, CB_Term.SelectedItem as Term, CB_Room.SelectedItem as Room, e.Week, e.ClassWeek, e.ClassTime, true);
                    return;
                }
            }
        }



    }
}
